package com.gobang.common.task;

import com.gobang.common.exception.MatchException;
import com.gobang.common.util.MatchUtils;
import com.gobang.domain.entity.MatchQueueEntry;
import com.gobang.service.*;
import com.gobang.service.impl.ScoreBasedMatchAlgorithm;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * 匹配调度器
 * 定时执行匹配算法，处理等待队列中的用户匹配
 *
 * @author gobang-team
 * @since 1.0.0
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class MatchScheduler {

    private final QueueManager queueManager;
    private final MatchAlgorithm matchAlgorithm;
    private final MessageService messageService;
    private final ConnectionManagerService connectionManagerService;
    private final GameRoomService gameRoomService; // 预留的游戏房间服务

    /**
     * 定时执行匹配算法
     * 每10秒执行一次匹配检查
     */
    @Scheduled(fixedRate = 10000) // 10秒
    public void executeMatch() {
        try {
            // 检查队列是否有等待用户
            int queueSize = queueManager.getQueueSize();
            if (queueSize < 2) {
                log.debug("队列用户数量不足，跳过匹配：{}", queueSize);
                return;
            }

            log.info("开始执行定时匹配，队列大小：{}", queueSize);

            // 获取等待队列
            List<MatchQueueEntry> waitingUsers = queueManager.getWaitingUsers();
            if (waitingUsers.size() < 2) {
                log.debug("获取到的等待用户数量不足：{}", waitingUsers.size());
                return;
            }

            // 执行批量匹配
            // [{1,2},{3,4}]
            List<MatchAlgorithm.MatchPair> matchPairs =
                    matchAlgorithm.batchMatch(waitingUsers);
            
            if (matchPairs.isEmpty()) {
                log.debug("本轮匹配未找到合适的对手");
                return;
            }

            log.info("本轮匹配成功配对数：{}", matchPairs.size());

            // 处理匹配成功的用户对
            for (MatchAlgorithm.MatchPair pair : matchPairs) {
                handleMatchSuccess(pair);
            }

        } catch (Exception e) {
            log.error("定时匹配执行异常", e);
        }
    }

    /**
     * 定时清理超时用户
     * 每30秒执行一次清理检查
     */
    @Scheduled(fixedRate = 30000) // 30秒
    public void cleanupTimeoutUsers() {
        try {
            log.debug("开始清理超时用户");

            // 清理等待时间超过5分钟的用户
            int cleanupCount = queueManager.cleanupTimeoutUsers(
                    MatchUtils.MAX_WAIT_TIME);
            
            if (cleanupCount > 0) {
                log.info("清理超时用户完成，清理数量：{}", cleanupCount);
            } else {
                log.debug("无超时用户需要清理");
            }

        } catch (Exception e) {
            log.error("清理超时用户异常", e);
        }
    }

    /**
     * 定时更新匹配状态
     * 每5秒向等待中的用户推送状态更新
     */
    @Scheduled(fixedRate = 5000) // 5秒
    public void updateMatchStatus() {
        try {
            // 获取所有等待用户
            List<MatchQueueEntry> waitingUsers = queueManager.getWaitingUsers();
            
            if (waitingUsers.isEmpty()) {
                log.debug("无等待用户需要状态更新");
                return;
            }

            log.debug("推送匹配状态更新，用户数：{}", waitingUsers.size());

            for (MatchQueueEntry user : waitingUsers) {
                try {
                    pushMatchStatusUpdate(user);
                } catch (Exception e) {
                    log.error("推送用户{}匹配状态异常", user.getUserId(), e);
                }
            }

        } catch (Exception e) {
            log.error("定时状态更新异常", e);
        }
    }

    /**
     * 处理匹配成功
     * 1. 匹配成功的后置处理：分配黑白棋、创建房间、连接状态的管理等
     * 2. 推送匹配成功WS消息
     */
    private void handleMatchSuccess(MatchAlgorithm.MatchPair pair) {
        MatchQueueEntry user1 = pair.getUser1();
        MatchQueueEntry user2 = pair.getUser2();
        
        try {
            log.info("处理匹配成功：用户{}({}) vs 用户{}({})", 
                    user1.getUserId(), user1.getCurrentScore(),
                    user2.getUserId(), user2.getCurrentScore());

            // 随机分配黑白方
            String user1Color = MatchUtils.randomPlayerColor();
            String user2Color = MatchUtils.getOpponentColor(user1Color);

            // 创建游戏房间
            GameRoomService.RoomCreationResult roomResult = gameRoomService.createRoom(
                    "BLACK".equals(user1Color) ? user1.getUserId() : user2.getUserId(),
                    "WHITE".equals(user1Color) ? user1.getUserId() : user2.getUserId()
            );

            if (!roomResult.isSuccess()) {
                log.error("游戏房间创建失败：{}", roomResult.getErrorMessage());
                handleRoomCreationFailure(user1.getUserId(), user2.getUserId());
                return;
            }

            String roomId = roomResult.getRoomId();
            String startTime = LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);

            // 从队列中移除已匹配的用户
            queueManager.removeFromQueue(user1.getUserId());
            queueManager.removeFromQueue(user2.getUserId());

            // 更新用户状态为游戏中
            connectionManagerService.updateUserStatus(user1.getUserId(), "gaming");
            connectionManagerService.updateUserStatus(user2.getUserId(), "gaming");

            // 将用户加入房间
            connectionManagerService.addUserToRoom(roomId, user1.getUserId());
            connectionManagerService.addUserToRoom(roomId, user2.getUserId());

            // 推送匹配成功通知
            notifyMatchSuccess(user1, user2, roomId, user1Color, user2Color, startTime);

            log.info("匹配成功处理完成：房间{}，用户{}({}) vs 用户{}({})", 
                    roomId, user1.getUserId(), user1Color, user2.getUserId(), user2Color);

        } catch (Exception e) {
            log.error("处理匹配成功异常：用户{} vs 用户{}", user1.getUserId(), user2.getUserId(), e);
            handleMatchFailure(user1.getUserId(), user2.getUserId());
        }
    }

    /**
     * 推送匹配状态更新
     */
    private void pushMatchStatusUpdate(MatchQueueEntry user) {
        try {
            int waitTime = (int) user.calculateWaitTime();
            int queuePosition = queueManager.getQueuePosition(user.getUserId());
            
            var statusMsg = MatchUtils.createMatchStatusUpdateMessage(
                    "MATCHING", waitTime, queuePosition);
            
            messageService.sendMatchStatusUpdate(user.getUserId(), statusMsg);
            
        } catch (Exception e) {
            log.error("推送用户{}匹配状态更新异常", user.getUserId(), e);
        }
    }

    /**
     * 通知匹配成功
     */
    private void notifyMatchSuccess(MatchQueueEntry user1, MatchQueueEntry user2, 
                                   String roomId, String user1Color, String user2Color, String startTime) {
        try {
            // 构造对手信息
            MatchService.MatchOpponentInfo opponent1 = new MatchService.MatchOpponentInfo(
                    user2.getUserId(), user2.getUsername(), user2.getCurrentScore());
            MatchService.MatchOpponentInfo opponent2 = new MatchService.MatchOpponentInfo(
                    user1.getUserId(), user1.getUsername(), user1.getCurrentScore());

            // 为用户1推送匹配成功消息
            var successMsg1 = MatchUtils.createMatchSuccessMessage(roomId, opponent1, user1Color, startTime);
            messageService.sendMatchSuccessNotification(user1.getUserId(), successMsg1);

            // 为用户2推送匹配成功消息
            var successMsg2 = MatchUtils.createMatchSuccessMessage(roomId, opponent2, user2Color, startTime);
            messageService.sendMatchSuccessNotification(user2.getUserId(), successMsg2);

        } catch (Exception e) {
            log.error("通知匹配成功异常：用户{} vs 用户{}", user1.getUserId(), user2.getUserId(), e);
        }
    }

    /**
     * 处理房间创建失败
     */
    private void handleRoomCreationFailure(Long userId1, Long userId2) {
        try {
            log.warn("房间创建失败，恢复用户状态：{}, {}", userId1, userId2);

            // 恢复用户在线状态
            connectionManagerService.updateUserStatus(userId1, "online");
            connectionManagerService.updateUserStatus(userId2, "online");

            // 发送错误通知
            messageService.sendErrorResponse(userId1, com.gobang.common.exception.ErrorCode.MATCH_ROOM_CREATE_FAILED, "匹配成功但房间创建失败");
            messageService.sendErrorResponse(userId2, com.gobang.common.exception.ErrorCode.MATCH_ROOM_CREATE_FAILED, "匹配成功但房间创建失败");

        } catch (Exception e) {
            log.error("处理房间创建失败异常", e);
        }
    }

    /**
     * 处理匹配失败
     */
    private void handleMatchFailure(Long userId1, Long userId2) {
        try {
            log.warn("匹配处理失败，恢复用户状态：{}, {}", userId1, userId2);

            // 确保用户状态正确
            connectionManagerService.updateUserStatus(userId1, "matching");
            connectionManagerService.updateUserStatus(userId2, "matching");

        } catch (Exception e) {
            log.error("处理匹配失败异常", e);
        }
    }

} 